#include "StdAfx.h"
#include "LoqModulatorStream.h"
#include "Loquendo/loqtts.h"
#include "WaveSample.h"
#include <queue>
#include "SampleBuffer.h"
#include "ModulatorTextProvider.h"
#include "Locator.h"

static int BUF_SIZE = 1024;
static int counter = 0;

static void MyPutDataCb(void* channel, void* pData, unsigned int nBytes, unsigned int* nSent, void* pUser)
{
	LoqModulatorStream* callback = (LoqModulatorStream*)pUser;
	callback->PutData(pData, nBytes);
}

typedef void (*SetCbFunction)(void(*func)(void* channel, void* pData, unsigned int nBytes, unsigned int* nSent, void* pUser), void* pUser);
LoqModulatorStream::LoqModulatorStream(void)
{
	instance = NULL;
	sampleIdx = 0;
	lastSample = NULL;
	textProvider = NULL;
	modulatorText = NULL;
}

LoqModulatorStream::~LoqModulatorStream(void)
{
	if(instance)
	{
		delete voice;
		delete instance;
	}
	if(lastSample)
	{
		delete lastSample;
		lastSample = NULL;
	}
	if(modulatorText)
	{
		delete modulatorText;
		modulatorText = NULL;
	}
}

static bool collectingSamples = false;
static void TTSCALLBACK myCallback(ttsEventType nReason, void * lData, void * pUser)
{
	LoqModulatorStream* callback = (LoqModulatorStream*)pUser;
	switch (nReason) {
	case TTSEVT_BOOKMARK:
		printf("Bookmark: %s\n", (char*)lData);
		break;
	case TTSEVT_DATA: 
	{ 
	   ttsPhonInfoType *p; 
	   p = (ttsPhonInfoType *) lData; 
	   //callback->events.push_back(p);
	   /* now access ttsPhonInfoType fields */ 
	   break;
	}
	case TTSEVT_ENDOFSPEECH:
		printf("endofspeech");
		callback->AddLastSample();
		collectingSamples = false;
		break;
	case TTSEVT_DEBUG:
	case TTSEVT_FREESPACE:
		break;
	default:
		break;
	}

}

void LoqModulatorStream::Initialize(ModulatorTextProvider* textProvider)
{
	//Load callback dll	
	HINSTANCE dll = NULL;	 
	dll = LoadLibrary ( _T("LoqAudioFile.dll") ) ;		 
	if ( dll != NULL )
	{
	  SetCbFunction lpSetCb = (SetCbFunction)GetProcAddress ( dll , "SetCb" ) ;	 
	  if ( lpSetCb != NULL ) 
	  {
		(*lpSetCb) ( MyPutDataCb, this ) ;
	  }
	}

	int samplingRate = 16000;
	instance = new CttsInstance(); 
	voice = new CttsVoice(instance, "Simon", samplingRate, "l"); 
	instance->SetAudio("LoqAudioFile", "loquendo.wav", "l", 0);
	instance->RegisterCallback(myCallback, this, 0);
	this->textProvider = textProvider;
}

void LoqModulatorStream::Reset()
{
	//instance->Stop();
	//delete instance;
	//delete voice;
}

void LoqModulatorStream::AddLastSample()
{
	sampleIdx = 0;
	if(lastSample!=NULL)
	{
		Locator::Instance()->GetModulatorBuffer()->Write(lastSample);
		delete lastSample;
	}
	lastSample = new Sample(BUF_SIZE);
}

static std::vector<int> chunkSizes;
void LoqModulatorStream::PutData(void* lData, unsigned int nBytes)
{
	short* sData = (short*)lData;
	int dataLength = nBytes/2;
	chunkSizes.push_back(dataLength);
	register int dataIdx = 0;
	while(dataIdx<dataLength)
	{
		if(sampleIdx==0)
		{
			AddLastSample();
		}
		for(; dataIdx<dataLength && sampleIdx<BUF_SIZE-2; dataIdx++)
		{
			double curSample = (double)sData[dataIdx];
			double nextSample = dataIdx<dataLength-1 ? (double)sData[dataIdx+1] : curSample;
			double step1 = curSample*.66 + nextSample*.33;//33% of the interval
			double step2 = curSample*.33 + nextSample*.66;//66% of the interval
			lastSample->data[sampleIdx++] = curSample;
			lastSample->data[sampleIdx++] = step1;
			lastSample->data[sampleIdx++] = step2;
		}
		if(sampleIdx == BUF_SIZE-1)
		{
			lastSample->data[sampleIdx] = sData[dataIdx];
			AddLastSample();
			lastSample->data[sampleIdx++] = sData[dataIdx];
			lastSample->data[sampleIdx++] = sData[dataIdx];
			dataIdx++;
		}
		else if(sampleIdx == BUF_SIZE-2)
		{
			lastSample->data[sampleIdx++] = sData[dataIdx];
			lastSample->data[sampleIdx] = sData[dataIdx];
			AddLastSample();
			lastSample->data[sampleIdx++] = sData[dataIdx];
			dataIdx++;
		}
		if(sampleIdx >= BUF_SIZE)
		{
			sampleIdx = 0;				
		}			
	}
}

Sample* LoqModulatorStream::GetData()
{
	if(!collectingSamples)
	{
		collectingSamples = true;
		if(!instance)
		{
			Initialize(Locator::Instance()->GetModulatorTextProvider());
		}
		sampleIdx = 0;
		if(modulatorText)
		{
			delete modulatorText;
			modulatorText = NULL;
		}
		modulatorText = textProvider->GetModulatorText();
		if(modulatorText)
		{
			instance->Read(modulatorText,
				  TTSBUFFER,  // "Input" is a text buffer 
				  TTSANSI,  // Input text is in ANSI 
				  TTSMULTILINE, //TTSAUTODETECT,// Default ReadingMode 
				  TTSNONBLOCKING); // event based 
		}
	}
	return NULL;
}